/*!
 * 简化的C文件扫描器
 * 
 * 只做基本的文件扫描和信息提取，复杂的分析交给LLM处理
 */

use anyhow::{Result, Context};
use std::path::{Path, PathBuf};
use walkdir::WalkDir;
use regex::Regex;

/// C项目文件信息
#[derive(Debug, Clone)]
pub struct CFile {
    pub path: PathBuf,
    pub content: String,
    pub includes: Vec<String>,
}


/// C项目扫描结果
#[derive(Debug)]
pub struct ScanResult {
    pub source_files: Vec<CFile>,
    pub total_lines: usize,
}

/// 文件扫描器 - 保持简单，让LLM处理复杂逻辑
pub struct FileScanner {
    include_regex: Regex,
}

impl FileScanner {
    pub fn new() -> Self {
        Self {
            // 简单的include匹配正则
            include_regex: Regex::new(r#"#include\s*[<"](.*?)[>"]"#).unwrap(),
        }
    }
    
    /// 扫描C项目目录
    pub fn scan_project(&self, project_path: &Path) -> Result<ScanResult> {
        log::info!("开始扫描C项目: {:?}", project_path);
        
        let mut source_files = Vec::new();
        let mut total_lines = 0;
        
        // 遍历项目目录
        for entry in WalkDir::new(project_path)
            .follow_links(false)
            .into_iter()
            .filter_map(|e| e.ok())
        {
            let path = entry.path();
            
            // 跳过目录
            if !path.is_file() {
                continue;
            }
            
            // 只处理.c文件
            let is_c_file = match path.extension().and_then(|s| s.to_str()) {
                Some("c") => true,
                _ => false,
            };
            
            if !is_c_file {
                continue; // 跳过非C源文件
            }
            
            // 读取文件内容
            let content = std::fs::read_to_string(path)
                .with_context(|| format!("无法读取文件: {:?}", path))?;
            
            total_lines += content.lines().count();
            
            // 提取基本信息
            let includes = self.extract_includes(&content);
            
            let c_file = CFile {
                path: path.to_path_buf(),
                content,
                includes,
            };
            
            // 添加到源文件列表
            source_files.push(c_file);
        }
        
        log::info!("扫描完成: {} 个源文件, 总计 {} 行代码", 
                  source_files.len(), total_lines);
        
        Ok(ScanResult {
            source_files,
            total_lines,
        })
    }
    
    /// 扫描单个文件
    pub fn scan_single_file(&self, file_path: &Path) -> Result<CFile> {
        let content = std::fs::read_to_string(file_path)
            .with_context(|| format!("无法读取文件: {:?}", file_path))?;
        
        // 检查是否为C源文件
        let is_c_file = match file_path.extension().and_then(|s| s.to_str()) {
            Some("c") => true,
            _ => false,
        };
        
        if !is_c_file {
            return Err(anyhow::anyhow!("不支持的文件类型: {:?}", file_path));
        }
        
        let includes = self.extract_includes(&content);
        
        Ok(CFile {
            path: file_path.to_path_buf(),
            content,
            includes,
        })
    }
    
    /// 提取include语句 - 简单正则匹配，不需要复杂的词法分析
    fn extract_includes(&self, content: &str) -> Vec<String> {
        self.include_regex
            .captures_iter(content)
            .filter_map(|cap| cap.get(1).map(|m| m.as_str().to_string()))
            .collect()
    }
    
    /// 获取文件的模块名（去掉路径和扩展名）
    pub fn get_module_name(file_path: &Path) -> String {
        file_path
            .file_stem()
            .and_then(|s| s.to_str())
            .unwrap_or("unknown")
            .to_string()
    }
    
    /// 检查是否为C关键字（需要在Rust中转义）
    pub fn is_c_keyword_needing_escape(name: &str) -> bool {
        matches!(name, 
            "type" | "match" | "loop" | "move" | "ref" | "self" | "Self" |
            "static" | "const" | "fn" | "let" | "mut" | "pub" | "use" |
            "mod" | "crate" | "super" | "enum" | "struct" | "trait" |
            "impl" | "for" | "while" | "if" | "else" | "return" |
            "break" | "continue" | "async" | "await" | "unsafe"
        )
    }
    
    /// 转义Rust关键字
    pub fn escape_rust_keyword(name: &str) -> String {
        if Self::is_c_keyword_needing_escape(name) {
            format!("r#{}", name)
        } else {
            name.to_string()
        }
    }
}
